﻿using System.Security.Cryptography;

namespace DDD.Domain.Abstract.GuidGenerator
{
    /// <summary>
    /// 前部变化 后部相同
    /// </summary>
    public class SequentialAsBinaryGuidGenerator : IGuidGenerator
    {
        public Guid Create()
        {
            byte version = (byte)4;
            byte variant = (byte)8;
            byte filterHighBit = 0b00001111;
            byte filterLowBit = 0b11110000;

            var randomBytes = new byte[8];
            RandomNumberGenerator.Create().GetBytes(randomBytes);

            long timestamp = DateTime.UtcNow.Ticks;

            byte[] timestampBytes = BitConverter.GetBytes(timestamp);
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(timestampBytes);
            }

            byte[] guidBytes = new byte[16];

            // AsString: dddddddd-dddd-Mddd-Ndrr-rrrrrrrrrrrr
            Buffer.BlockCopy(timestampBytes, 0, guidBytes, 0, 6); // 时间戳前6个字节，共48位
            guidBytes[6] = (byte)((version << 4) | ((timestampBytes[6] & filterLowBit) >> 4)); // 高4位为版本 | 低4位取时间戳序号[6]的元素的高4位
            guidBytes[7] = (byte)(((timestampBytes[6] & filterHighBit) << 4) | ((timestampBytes[7] & filterLowBit) >> 4)); // 高4位取：[6]低4位 | 低4位取：[7]高4位
            guidBytes[8] = (byte)((variant << 4) | (timestampBytes[7] & filterHighBit)); // 高4位为：变体 | 低4位取：[7]低4位
            Buffer.BlockCopy(randomBytes, 0, guidBytes, 9, 7); // 余下7个字节由随机数组填充

            // .NET中，Data1、Data2、Data3 块 分别视为 Int32、Int16、Int16，在小端系统，需要翻转这3个块。
            Array.Reverse(guidBytes, 0, 4);
            Array.Reverse(guidBytes, 4, 2);
            Array.Reverse(guidBytes, 6, 2);

            return new Guid(guidBytes);
        }
    }
}
